package
{
	import ResourcePackage.ExternalResource;
	import ResourcePackage.Resource;
	
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.*;
	import flash.external.ExternalInterface;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	
	import flashx.textLayout.elements.OverflowPolicy;
	import flashx.textLayout.formats.TextAlign;

	/*
	Step 1: Sort data URL-ByteArray-Resource;
	Step 2: Load all resource;
	*/
	public class StateLoading extends State
	{
		public var Loading:Class;
		
		protected var exResource:Vector.<ExternalResource> = new Vector.<ExternalResource>();
		protected var loader:URLLoader;
		protected var converter:Loader;
		protected var count:uint;
		protected var loadedBytes:String = "";
		protected var loadedFiles:String = "";
		protected var parent:State = null;
		protected var modeless:Boolean;
		protected var visible:Boolean;
		protected var description:String;
		protected var isPushedInStack:Boolean = true;
		protected static var statesOutOfStack:Vector.<StateLoading> = new Vector.<StateLoading>();
		protected var isComplete:Boolean = false;
		public static function Load(description:String, exResource:Vector.<ExternalResource>, parent:State):void
		{
			var i:int = 0;
			while(true)
			{
				if(i >= statesOutOfStack.length)
				{
					break;
				}
				if(statesOutOfStack[i].isComplete)
				{
					delete statesOutOfStack[i];
					statesOutOfStack.splice(i,1);
				}
				else
				{
					i++;
				}
			}
			var state:StateLoading = new StateLoading(description,exResource, parent);
			state.isPushedInStack = false;
			statesOutOfStack.push(state);
			state.Init();
		}
		public function StateLoading(description:String, exResource:Vector.<ExternalResource>
									 , parent:State, modeless:Boolean = false, visible:Boolean = true)
		{
			super();
			if(exResource)
			{
				for(var i:int = 0;i<exResource.length;i++)
				{
					if(exResource[i].GetLoadType() == ExternalResource.TYPE_FromURL)
					{
						this.exResource.push(exResource[i]);
					}
				}
				for(i = 0;i<exResource.length;i++)
				{
					if(exResource[i].GetLoadType() == ExternalResource.TYPE_FromByteArray)
					{
						this.exResource.push(exResource[i]);
					}
				}
				for(i = 0;i<exResource.length;i++)
				{
					if(exResource[i].GetLoadType() == ExternalResource.TYPE_FromResource)
					{
						this.exResource.push(exResource[i]);
					}
				}
			}
			this.parent = parent;
			this.modeless = modeless;
			this.visible = visible;
			this.description = description;
			
		}
		public override function Init():void
		{
			if(this.exResource.length <= 0)
			{
				loadedBytes = "Load all finish";
				isComplete = true;
				if(isPushedInStack)
				{
					Game.GetStateStack().RemoveStateAt(this.stateIndex);
				}
				//Game.GetStateStack().Pop();
				parent.LoadComplete(true, description);
				return;
			}
			count = 0;
			LoadResourceNext();
		}
		protected function completeHandler(event:Event):void 
		{
			ReceiveData(event);
			count++;
			if(count < exResource.length)
			{
				LoadResourceNext();
			}
			else
			{
				loadedBytes = "Load all finish";
				isComplete = true;
				if(isPushedInStack)
				{
					Game.GetStateStack().RemoveStateAt(this.stateIndex);
				}
				//Game.GetStateStack().Pop();
				parent.LoadComplete(true, description);
				return;
			}
		}
		private function configureListeners(dispatcher:IEventDispatcher):void {
			dispatcher.addEventListener(Event.COMPLETE, completeHandler);
			dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
			dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
			//dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
		}
		protected function LoadResourceNext():void
		{
			if(this.exResource[count].resourceDes.GetResourceType() == Resource.TYPE_ByteArray)
			{
				if(this.exResource[count].GetLoadType() == ExternalResource.TYPE_FromURL)
				{
					loader = new URLLoader();
					loader.dataFormat = URLLoaderDataFormat.BINARY;
					configureListeners(loader);
					var request:URLRequest = new URLRequest(this.exResource[count].GetURL());
					loader.load(request);
				}
				else
				{
					
				}
			}
			else // image, movie
			{
				if(this.exResource[count].GetLoadType() == ExternalResource.TYPE_FromURL)
				{
					converter = new Loader();
					configureListeners(converter.contentLoaderInfo);
					var request:URLRequest = new URLRequest(this.exResource[count].GetURL());
					converter.load(request);
				}
				else if(this.exResource[count].GetLoadType() == ExternalResource.TYPE_FromResource)
				{
					if(this.exResource[count].GetResourceSource().GetResourceType() == Resource.TYPE_ByteArray)
					{
						converter = new Loader();
						configureListeners(converter.contentLoaderInfo);
						converter.loadBytes(this.exResource[count].GetResourceSource().GetData() as ByteArray);
					}
					else
					{
						
					}
				}
				else // from byte array
				{
					converter = new Loader();
					configureListeners(converter.contentLoaderInfo);
					converter.loadBytes(this.exResource[count].GetByteArray());
				}
			}
		}
		protected function ReceiveData(event:Event):void
		{
			if(this.exResource[count].resourceDes.GetResourceType() == Resource.TYPE_ByteArray)
			{
				if(this.exResource[count].GetLoadType() == ExternalResource.TYPE_FromURL)
				{
					this.exResource[count].resourceDes.SetData(event.target.data); //byte array
					if(this.exResource[count].loadCompleteCallback != null) this.exResource[count].loadCompleteCallback();
				}
				else
				{
					
				}
			}
			else //image, movie
			{
				var object:Object = event.currentTarget.content;
				this.exResource[count].resourceDes.SetData(object);
				if(object != null && exResource[count].resourceDes.GetResourceType() == Resource.TYPE_MovieClip)
				{
					try
					{
						object.SetContainer(Game.GetInstance());
					}
					catch(e:Error)
					{
						trace("completeHandlerConverter: " + e.message);
					}
				}
				if(this.exResource[count].loadCompleteCallback != null) this.exResource[count].loadCompleteCallback();
			}
		}
		
		protected function httpStatusHandler(event:HTTPStatusEvent):void {
			loadedBytes = "httpStatusHandler " + event;
		}
		protected function ioErrorHandler(event:IOErrorEvent):void {
			trace("ioErrorHandler: " + event);
			loadedBytes = "IO error " + event.text;
			isComplete = true;
			if(isPushedInStack)
			{
				Game.GetStateStack().RemoveStateAt(this.stateIndex);
			}
			//Game.GetStateStack().Pop();
			parent.LoadComplete(false, description);
		}
		protected function progressHandler(event:ProgressEvent):void {
			trace("progressHandler: bytesLoaded=" + event.bytesLoaded + " bytesTotal=" + event.bytesTotal);
			loadedBytes = event.bytesLoaded.toString() + " bytes";
		}
		public override function Render(g:MyGraphics):void
		{
			if(this.visible)
			{
				g.Clear(0xFF000000);
				g.SetTextAlign(TextAlign.CENTER);
				g.SetTextSize(50);
				g.DrawString("Loading",Game.GetWidth()/2,Game.GetHeight()/2 - 50,0xFFFFFFFF);
				g.DrawRect(100,400,Game.GetWidth() - 200,20,0xFFFFFF,1);
				g.FillRect(100,400,(Game.GetWidth() - 200)*count/this.exResource.length,20,0xFFFFFF);
			}
			else
			{
				if(this.stateIndex - 1 >= 0)
					Game.GetStateStack().GetStateAt(this.stateIndex - 1).Render(g);
			}
		}
		public override function Update(dt:int):void
		{
			if(this.modeless == true) // ????
			{
				if(this.stateIndex - 1 >= 0)
					Game.GetStateStack().GetStateAt(this.stateIndex - 1).Update(dt);
			}
		}
		public override function GetStateName():String
		{
			return "StateLoading";
		}
		public override function Release():void
		{

		}
	}
}